<template>
  <div class="service-container">
    <!--start of workspace-tree-dialog-->
    <el-dialog
      :append-to-body="true"
      :visible.sync="workSpaceModalVisible"
      width="60%"
      :title="$t('services.k8s.selectFileToSync')"
      class="fileTree-dialog"
    >
      <GitFileTree
        ref="worktree"
        :codehostId="source.codehostId"
        :repoName="source.repoName"
        :repoOwner="source.repoOwner"
        :branchName="source.branchName"
        :remoteName="source.remoteName"
        :namespace="source.namespace"
        :gitType="source.gitType"
        @getPreloadServices="getPreloadServices"
        :showTree="workSpaceModalVisible"
      />
    </el-dialog>
    <!--end of workspace-tree-dialog-->
    <el-dialog
      :title="currentUpdatedServiceName ? $t('services.common.updateService') : $t('services.k8s.createServiceSyncFromRepo')"
      width="720px"
      center
      @close="closeSelectRepo"
      :append-to-body="true"
      :close-on-click-modal="false"
      custom-class="dialog-source"
      :visible.sync="dialogImportFromRepoVisible"
    >
      <div class="from-code-container">
        <el-form :model="source" :rules="sourceRules" label-position="left" ref="sourceForm" label-width="130px">
          <el-form-item
            :label="$t('repository.info.provider')"
            prop="codehostId"
            :rules="{required: true, message: $t('repository.prompt.selectGitProvider'), trigger: 'change'}"
          >
            <el-select
              v-model="source.codehostId"
              size="small"
              style="width: 100%;"
              :placeholder="$t('repository.prompt.selectGitProvider')"
              @change="getRepoOwnerById(source.codehostId)"
              filterable
            >
              <el-option
                v-for="(host,index) in allCodeHosts"
                :key="index"
                :label="host.address + '('+host.alias+')'"
                :value="host.id"
              >{{host.address + '('+host.alias+')'}}</el-option>
            </el-select>
          </el-form-item>
          <el-form-item
            :label="$t('repository.info.orgOrUser')"
            prop="repoOwner"
            :rules="{required: true, message: $t('repository.prompt.selectOrgOrUsername'), trigger: 'change'}"
          >
            <el-select
              v-model.trim="source.repoOwner"
              size="small"
              style="width: 100%;"
              @change="getRepoNameById(source.codehostId,source.repoOwner)"
              @clear="clearRepoOwner"
              remote
              :remote-method="searchRepoOwner"
              :loading="searchRepoOwnerLoading"
              allow-create
              clearable
              :placeholder="$t('repository.prompt.selectOrgOrUsername')"
              filterable
            >
              <el-option v-for="(repo,index) in codeInfo['repoOwners']" :key="index" :label="repo.path" :value="repo.path">
                <span>{{repo.path}}</span>
              </el-option>
            </el-select>
          </el-form-item>
          <template>
            <el-form-item
              :label="$t(`global.repository`)"
              prop="repoName"
              :rules="{required: true, message: $t('repository.prompt.selectRepo'), trigger: 'change'}"
            >
              <el-select
                @change="getBranchInfoById(source.codehostId,source.repoOwner,source.repoName,source)"
                @clear="clearRepoName"
                v-model.trim="source.repoName"
                remote
                :remote-method="searchRepoName"
                :loading="searchRepoNameLoading"
                style="width: 100%;"
                allow-create
                clearable
                size="small"
                :placeholder="$t('repository.prompt.selectRepo')"
                filterable
              >
                <el-option v-for="(repo,index) in codeInfo['repos']" :key="index" :label="repo.name" :value="repo.name"></el-option>
              </el-select>
            </el-form-item>
            <el-form-item
              :label="$t('repository.info.branch')"
              prop="branchName"
              :rules="{required: true, message: $t('repository.prompt.selectBranch'), trigger: 'change'}"
            >
              <el-select
                v-model.trim="source.branchName"
                :placeholder="$t('repository.prompt.selectBranch')"
                style="width: 100%;"
                size="small"
                filterable
                allow-create
                clearable
              >
                <el-option
                  v-for="(branch,branch_index) in codeInfo['branches']"
                  :key="branch_index"
                  :label="branch.name"
                  :value="branch.name"
                ></el-option>
              </el-select>
            </el-form-item>
            <el-form-item
              prop="path"
              :label="$t('repository.info.fileOrFolder')"
              :rules="{required: true, message: $t('repository.prompt.selectFileOrFolder'), trigger: 'change'}"
            >
              {{ source.path}}
              <el-button
                v-if="showSelectPath"
                @click="openFileTree"
                :disabled="!showSelectFileBtn"
                type="primary"
                icon="el-icon-plus"
                plain
                size="mini"
                circle
              ></el-button>
              <span v-if="disabledReload" class="preload-error">{{$t('services.k8s.serviceNameMismatch')}}</span>
              <div class="preload-container" v-if="source.services && source.services.length > 0">
                <span class="contains">{{$t('services.k8s.servicesIncluded')}}</span>
                <span v-for="(service,index) in source.services" :key="index" class="service-name">{{service}}</span>
              </div>
            </el-form-item>
          </template>
        </el-form>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button size="small" @click="dialogImportFromRepoVisible=false" plain>{{$t(`global.cancel`)}}</el-button>
        <el-button
          size="small"
          type="primary"
          :loading="dialogImportFromRepoLoading"
          :disabled="disabledReload"
          @click="loadRepoService()"
          plain
        >{{$t('global.sync')}}</el-button>
      </span>
    </el-dialog>
    <ImportFromTemplate
      :projectName="projectName"
      :currentUpdatedServiceName="currentUpdatedServiceName"
      :currentUpdatedServiceTemplateId="currentUpdatedServiceTemplateId"
      :currentUpdatedServiceVariableYaml="currentUpdatedServiceVariableYaml"
      :currentUpdatedServiceVariableKvs="currentUpdatedServiceVariableKvs"
      :currentUpdatedServiceAutoSync="currentUpdatedServiceAutoSync"
      :dialogImportFromYamlVisible.sync="openImportYamlDialog"
      @importYamlSuccess="importYamlSuccess"
    />
    <ImportFromNamespace
      :projectName="projectName"
      :dialogImportFromNamespaceVisible.sync="openImportNamespaceDialog"
      :importServiceFromNamespaceSuccess="importServiceFromNamespaceSuccess"
    />
    <div class="menu-container">
      <div class="function-container">
          <div class="source-dropdown">
            <el-radio-group v-model="mode" size="mini">
              <el-tooltip effect="dark" :content="$t('services.common.servicesManagement')" placement="top">
                <el-radio-button label="edit">
                  <i class="iconfont iconiconlog"></i>
                </el-radio-button>
              </el-tooltip>
              <el-tooltip effect="dark" :content="$t('services.common.serviceOrchestration')" placement="top">
                <el-radio-button v-hasPermi="{projectName: projectName, action: 'edit_service'}" label="arrange">
                  <i class="iconfont iconvery-sort"></i>
                </el-radio-button>
              </el-tooltip>
            </el-radio-group>
          </div>
          <div class="operation">
            <el-tooltip effect="dark" :content="$t('services.k8s.inputByManual')" placement="top">
              <el-button
                v-if="deployType==='k8s'"
                v-hasPermi="{type:'project',projectName: projectName, action: 'create_service',isBtn:true}"
                size="mini"
                icon="el-icon-plus"
                @click="createService('platform')"
                plain
                circle
              ></el-button>
            </el-tooltip>
            <el-tooltip effect="dark" :content="$t('services.common.syncFromRepository')" placement="top">
              <el-button
                v-if="deployType==='k8s'"
                v-hasPermi="{type:'project',projectName: projectName, action: 'create_service',isBtn:true}"
                size="mini"
                @click="createService('repo')"
                icon="iconfont icon icongit"
                plain
                circle
              ></el-button>
            </el-tooltip>
            <el-dropdown placement="bottom" style="margin-left: 10px;">
              <el-button
                size="mini"
                icon="iconfont icon iconvery-template"
                plain
                circle
                v-hasPermi="{type:'project',projectName: projectName, action: 'create_service',isBtn:true}"
              ></el-button>
              <el-dropdown-menu slot="dropdown">
                <el-dropdown-item @click.native="createService('template')">{{$t('services.common.syncFromTemplate')}}</el-dropdown-item>
                <el-dropdown-item @click.native="createService('namespace')">{{$t('services.k8s.importFromK8sNamespace')}}</el-dropdown-item>
              </el-dropdown-menu>
            </el-dropdown>
          </div>
      </div>
    </div>
    <div class="tree-container">
      <keep-alive>
        <el-tree
          v-if="mode==='edit'"
          ref="serviceTree"
          :data="filteredServices"
          :show-checkbox="false"
          node-key="service_name"
          @node-click="selectService"
          default-expand-all
          highlight-current
          check-on-click-node
          :indent="0"
          :expand-on-click-node="false"
        >
          <span
            @mouseover="setHovered(data.service_name)"
            @mouseleave="unsetHovered(data.service_name)"
            class="service-mgr-tree-node"
            slot-scope="{ node, data }"
          >
            <span class="service-status" :class="data.status"></span>
            <i v-if="data.type==='k8s'" class="service-type iconfont iconrongqifuwu"></i>
            <el-tooltip v-if="isShared(data)" effect="light" placement="top">
              <div slot="content">
                <span>{{`${$t('services.k8s.serviceName')}:${data.service_name}`}}</span>
                <span>
                  <br />
                  {{`${$t('services.k8s.originProject')}:${data.product_name}`}}
                </span>
              </div>
              <div class="tree-service-name" :class="{'kind':data.type==='kind'?true:false}">
                <span class="label">{{node.label}}</span>
              </div>
            </el-tooltip>
            <span v-else class="tree-service-name" :class="{'kind':data.type==='kind'?true:false}">
              <span class="label">{{node.label}}</span>
            </span>
            <template>
              <el-button
                v-if="data.status==='named' && data.type==='k8s'"
                type="text"
                size="mini"
                class="operation-container"
                icon="el-icon-edit-outline"
                @click.stop="() => reEditServiceName(node, data)"
              ></el-button>
              <span v-if="isShared(data)">
                <el-tag
                  v-if="data.type === 'k8s'"
                  type="info"
                  effect="plain"
                  size="mini"
                >{{$t('services.k8s.sharedService')}}</el-tag>
              </span>
              <span :style="{'visibility': showHover[data.service_name] ? 'visible': 'hidden'}" class="operation-container">
                <el-button
                  v-hasPermi="{projectName: projectName, action: 'delete_service',isBtn:true}"
                  v-if="(data.status === 'added'||data.status === 'named')"
                  type="text"
                  size="mini"
                  icon="el-icon-close"
                  @click.stop="() => deleteService(node, data)"
                ></el-button>
                <el-button
                  v-hasPermi="{projectName: projectName, action: 'edit_service',isBtn:true}"
                  v-if="data.source && (data.source === 'gitee' || data.source === 'gerrit'|| data.source === 'gitlab' || data.source==='github' || data.source==='template' ) && data.type==='k8s' && data.product_name=== projectName "
                  type="text"
                  size="mini"
                  icon="el-icon-refresh"
                  @click="() => refreshService(node, data)"
                ></el-button>
              </span>
            </template>
          </span>
        </el-tree>
      </keep-alive>
      <div v-if="showNewServiceInput && mode==='edit'" class="add-new-service">
        <el-form :model="service" :rules="serviceRules" ref="newServiceNameForm" @submit.native.prevent>
          <el-form-item label prop="newServiceName">
            <span class="service-status new"></span>
            <i class="service-type iconfont iconrongqifuwu"></i>
            <el-input
              v-model="service.newServiceName"
              size="mini"
              autofocus
              ref="serviceNamedRef"
              @blur="inputServiceNameDoneWhenBlur"
              @keyup.enter.native="inputServiceNameDoneWhenBlur"
              :placeholder="$t('services.common.inputServiceName')"
            ></el-input>
          </el-form-item>
        </el-form>
      </div>
      <el-tree
        v-if="mode==='arrange' && deployType === 'k8s'"
        ref="arrangeTreeRef"
        :data="serviceGroup"
        :show-checkbox="false"
        node-key="id"
        draggable
        :allow-drop="allowDrop"
        :allow-drag="allowDrag"
        @node-drop="handleDrop"
        @node-drag-start="startDrag"
        @node-drag-end="endDrag"
        default-expand-all
        :expand-on-click-node="false"
        class="arrange-tree"
      >
        <span class="service-mgr-tree-node" slot-scope="{ node, data }">
          <span class="service-status" :class="data.status"></span>
          <span class="tree-service-name">{{ node.label }}</span>
        </span>
      </el-tree>
      <div v-if="mode==='arrange' && showDragContainer" class="add-new-service drag-container"></div>
    </div>
    <div v-if="mode==='edit'" class="search-container">
      <el-input
        :placeholder="$t('services.common.searchService')"
        size="small"
        clearable
        suffix-icon="el-icon-search"
        v-model="searchService"
      ></el-input>
    </div>
  </div>
</template>

<script>
import GitFileTree from '@/components/common/gitFileTree.vue'
import ImportFromTemplate from './importFromTemplate.vue'
import ImportFromNamespace from './importFromNamespace.vue'
import {
  deleteProjectServiceAPI,
  getSingleProjectAPI,
  getCodeSourceMaskedAPI,
  getRepoOwnerByIdAPI,
  getRepoNameByIdAPI,
  getBranchInfoByIdAPI,
  loadRepoServiceAPI,
  updateLoadRepoServiceAPI,
  validPreloadService,
  getCodeProviderAPI,
  updateServicesOrchestrationAPI
} from '@api'
export default {
  props: {
    services: {
      type: Array,
      required: true
    },
    currentServiceYamlKinds: {
      type: Object,
      required: true,
      default: null
    },
    projectInfo: {
      type: Object,
      required: true,
      default: null
    },
    yamlChange: {
      type: Boolean,
      required: true
    }
  },
  data () {
    return {
      mode: 'edit',
      service: {
        newServiceName: ''
      },
      showHover: {},
      searchService: '',
      currentUpdatedServiceName: '',
      currentUpdatedServiceTemplateId: '',
      currentUpdatedServiceAutoSync: false,
      currentUpdatedServiceVariableYaml: '',
      currentUpdatedServiceVariableKvs: [],
      serviceGroup: [],
      allCodeHosts: [],
      openImportYamlDialog: false,
      openImportNamespaceDialog: false,
      dialogImportFromRepoLoading: false,
      searchRepoNameLoading: false,
      searchRepoOwnerLoading: false,
      workSpaceModalVisible: false,
      dialogImportFromRepoVisible: false,
      showNewServiceInput: false,
      showDragContainer: false,
      showSelectPath: true,
      disabledReload: false,
      codeInfo: {
        repoOwners: [],
        repos: [],
        branches: []
      },
      source: {
        codehostId: null,
        repoOwner: '',
        repoName: '',
        branchName: '',
        remoteName: '',
        gitType: '',
        services: [],
        path: '',
        isDir: false
      },
      previousNodeKey: ''
    }
  },

  methods: {
    isShared (data) {
      return (
        data.type !== 'kind' &&
        data.visibility === 'public'
      )
    },
    setHovered (name) {
      this.$nextTick(() => {
        this.$set(this.showHover, name, true)
      })
    },
    unsetHovered (name) {
      this.$nextTick(() => {
        this.$set(this.showHover, name, false)
      })
    },
    getServiceGroup () {
      this.serviceGroup = []
      const projectName = this.projectName
      getSingleProjectAPI(projectName).then(res => {
        res.services.push([])
        res.services.forEach((order, orderIndex) => {
          this.serviceGroup.push({
            label: `${this.$t(
              'services.common.startupSequence'
            )} ${orderIndex}`,
            id: orderIndex,
            children: []
          })
          order.forEach((service, serviceIndex) => {
            this.serviceGroup[orderIndex].children.push({
              label: service,
              id: `${orderIndex}-${serviceIndex}`,
              children: []
            })
          })
        })
      })
    },
    openFileTree () {
      if (this.showSelectFileBtn) {
        this.workSpaceModalVisible = true
      }
    },
    getPreloadServices (val) {
      this.source.path = val.path
      this.source.isDir = val.isDir
      this.source.services = val.services
      this.workSpaceModalVisible = false
      const codehostId = this.source.codehostId
      const repoName = this.source.repoName
      const branchName = this.source.branchName
      const remoteName = this.source.remoteName
      const serviceName = this.source.serviceName
      const namespace = this.source.namespace
      const path = val.path
      const isDir = this.source.isDir
      if (serviceName) {
        validPreloadService(
          codehostId,
          namespace,
          repoName,
          branchName,
          path,
          serviceName,
          isDir,
          remoteName
        ).then(
          res => {
            this.disabledReload = false
          },
          () => {
            this.disabledReload = true
          }
        )
      }
    },
    loadRepoService () {
      const codehostId = this.source.codehostId
      const repoOwner = this.source.repoOwner
      const repoName = this.source.repoName
      const branchName = this.source.branchName
      const remoteName = this.source.remoteName
      const path = this.source.path
      const isDir = this.source.isDir
      const namespace = this.source.namespace
      const payload = {
        product_name: this.projectName,
        visibility: 'private',
        is_dir: isDir,
        type: 'k8s',
        path: path
      }
      this.$refs.sourceForm.validate(valid => {
        if (valid) {
          this.dialogImportFromRepoLoading = true
          const reqApi = this.currentUpdatedServiceName
            ? updateLoadRepoServiceAPI
            : loadRepoServiceAPI
          reqApi(
            this.projectName,
            codehostId,
            repoOwner,
            repoName,
            branchName,
            remoteName,
            namespace,
            payload
          )
            .then(res => {
              this.$emit('onRefreshService')
              this.$emit('update:showNext', true)
              this.getServiceGroup()
              this.dialogImportFromRepoVisible = false
              this.$message({
                message: this.$t('services.k8s.importServiceSuccess'),
                type: 'success'
              })
              if (this.source.services && this.source.services.length > 0) {
                const firstServiceName = this.source.services[0]
                this.setServiceSelected(firstServiceName)
                this.$router.replace({
                  query: { service_name: firstServiceName, rightbar: 'var' }
                })
                this.$nextTick(() => {
                  this.$emit('onShowJoinToEnvBtn', true)
                })
              }
            })
            .finally(() => {
              this.dialogImportFromRepoLoading = false
            })
        } else {
          return false
        }
      })
    },
    closeSelectRepo () {
      this.source = {
        codehostId: null,
        repoOwner: '',
        repoName: '',
        branchName: '',
        remoteName: '',
        gitType: ''
      }
      this.showSelectPath = true
      this.$refs.sourceForm.resetFields()
    },
    startDrag (node) {
      const parent = node.parent
      this.$refs.arrangeTreeRef.root.childNodes.forEach(child => {
        if (parent !== child) {
          child.expanded = false
        }
      })
      this.$refs.arrangeTreeRef.$el.scrollTo({
        top: 0,
        behavior: 'smooth'
      })
      this.showDragContainer = true

      const serviceLength = this.serviceGroup.length
      if (this.serviceGroup[serviceLength - 1].children.length) {
        this.serviceGroup.push({
          label: `${$t('services.common.startupSequence')} ${serviceLength}`,
          id: serviceLength,
          children: []
        })
      }
    },
    endDrag () {
      this.$refs.arrangeTreeRef.root.childNodes.forEach(child => {
        child.expanded = true
      })
      this.showDragContainer = false
    },
    allowDrag (draggingNode) {
      return !draggingNode.data.label.includes(
        this.$t('services.common.startupSequence')
      )
    },
    allowDrop (draggingNode, dropNode, type) {
      if (
        dropNode.data.label.includes(
          this.$t('services.common.startupSequence')
        ) &&
        type === 'inner'
      ) {
        return true
      } else if (
        !dropNode.data.label.includes(
          this.$t('services.common.startupSequence')
        ) &&
        type !== 'inner'
      ) {
        return true
      } else if (
        dropNode.data.label.includes(
          this.$t('services.common.startupSequence')
        ) &&
        type === 'prev'
      ) {
        return false
      }
    },
    handleDrop (draggingNode, dropNode, dropType, ev) {
      const services = []
      this.serviceGroup.forEach((order, orderIndex) => {
        if (order.children.length > 0) {
          const serviceStringArray = order.children.map(service => {
            return service.label
          })
          services.push(serviceStringArray)
        }
      })
      updateServicesOrchestrationAPI(this.projectName, { services })
    },
    async createService (cmd) {
      if (this.yamlChange && this.filteredServices.length > 0) {
        this.askSaveYamlConfig()
        return
      }
      const key = this.$utils.rsaEncrypt()
      const res = await getCodeProviderAPI(key)
      if (cmd && this.deployType === 'k8s') {
        if (cmd === 'platform') {
          this.showNewServiceInput = true
          this.mode = 'edit'
          this.$nextTick(() => {
            this.$refs.serviceNamedRef.focus()
          })
        } else if (cmd === 'repo') {
          this.currentUpdatedServiceName = ''
          if (res && res.length > 0) {
            this.dialogImportFromRepoVisible = true
            this.showNewServiceInput = false
            this.mode = 'edit'
            this.showSelectPath = true
            this.disabledReload = false
            const key = this.$utils.rsaEncrypt()
            getCodeSourceMaskedAPI(key).then(res => {
              this.allCodeHosts = res.filter(element => {
                return element.type !== 'other'
              })
            })
          } else {
            this.$emit('onAddCodeSource', true)
          }
        } else if (cmd === 'template') {
          this.currentUpdatedServiceName = ''
          this.openImportYamlDialog = true
        } else if (cmd === 'namespace') {
          this.openImportNamespaceDialog = true
        }
      }
    },
    inputServiceNameDoneWhenBlur () {
      if (this.service.newServiceName === '') {
        this.showNewServiceInput = false
      } else {
        this.$refs.newServiceNameForm.validate(valid => {
          if (valid) {
            const val = this.service.newServiceName
            this.previousNodeKey = val
            const data = {
              label: val,
              status: 'named',
              service_name: val,
              type: this.deployType ? this.deployType : 'k8s',
              visibility: 'private',
              product_name: this.projectName
            }
            this.setServiceSelected(data.service_name)
            // Changes in services data will trigger watch.
            // At this time, the query of $route has not changed, and the newly created service will not be displayed.
            this.$route.query.service_name = data.service_name
            this.$router.replace({
              query: { service_name: data.service_name, rightbar: 'help' }
            })
            this.services.push(data)
            this.$emit('onSelectServiceChange', data)
            this.showNewServiceInput = false
            this.service.newServiceName = ''
          }
        })
      }
    },
    reEditServiceName (node, data) {
      const service = this.$utils.cloneObj(data)
      this.$nextTick(() => {
        this.$refs.serviceTree.remove(node)
      })
      const index = this.filteredServices.findIndex(
        d => d.service_name === service.service_name
      )
      this.services.splice(index, 1)
      this.showNewServiceInput = true
      this.service.newServiceName = service.service_name
      this.$nextTick(() => {
        this.$refs.serviceNamedRef.focus()
      })
    },
    getInitRepoInfo (source) {
      const codehostId = source.codehostId
      const repoOwner = source.repoOwner
      const repoName = source.repoName
      this.$set(this, 'codeInfo', {
        repoOwners: [],
        repos: [],
        branches: []
      })
      const key = this.$utils.rsaEncrypt()
      getCodeSourceMaskedAPI(key).then(res => {
        this.allCodeHosts = res.filter(element => {
          return element
        })
      })
      getRepoOwnerByIdAPI(codehostId).then(res => {
        this.$set(this.codeInfo, 'repoOwners', res)
        const item = this.codeInfo.repoOwners.find(item => {
          return item.path === repoOwner
        })
        const type = item ? item.kind : 'group'
        getRepoNameByIdAPI(codehostId, type, encodeURI(repoOwner)).then(res => {
          this.$set(this.codeInfo, 'repos', res)
        })
      })
      getBranchInfoByIdAPI(codehostId, source.namespace, repoName).then(res => {
        this.$set(this.codeInfo, 'branches', res)
      })
    },
    searchRepoName (query) {
      this.searchRepoNameLoading = true
      const repoOwner = this.source.repoOwner
      const item = this.codeInfo.repoOwners.find(item => {
        return item.path === repoOwner
      })
      const type = item ? item.kind : 'group'
      const id = this.source.codehostId
      getRepoNameByIdAPI(id, type, encodeURI(repoOwner), query).then(res => {
        this.searchRepoNameLoading = false
        this.$set(this.codeInfo, 'repos', res)
      })
    },
    clearRepoName () {
      const repoOwner = this.source.repoOwner
      const item = this.codeInfo.repoOwners.find(item => {
        return item.path === repoOwner || item.name === repoOwner
      })
      const type = item ? item.kind : 'group'
      const id = this.source.codehostId
      getRepoNameByIdAPI(id, type, encodeURI(repoOwner), '').then(res => {
        this.$set(this.codeInfo, 'repos', res)
      })
      this.source.branchName = ''
      this.source.path = ''
      this.source.services = []
      this.$set(this.codeInfo, 'branches', [])
    },
    getRepoNameById (id, repoOwner, key = '') {
      const item = this.codeInfo.repoOwners.find(item => {
        return item.path === repoOwner || item.name === repoOwner
      })
      const type = item ? item.kind : 'group'
      this.$refs.sourceForm.clearValidate()
      if (repoOwner) {
        getRepoNameByIdAPI(id, type, encodeURI(repoOwner), key).then(res => {
          this.$set(this.codeInfo, 'repos', res)
        })
      }
      this.source.repoName = ''
      this.source.branchName = ''
      this.source.path = ''
      this.source.services = []
    },
    searchRepoOwner (query) {
      this.searchRepoOwnerLoading = true
      const id = this.source.codehostId
      const type = this.allCodeHosts.find(item => {
        return item.id === id
      }).type
      if (type === 'github' && query !== '') {
        const items = this.$utils.filterObjectArrayByKey(
          'path',
          query,
          this.codeInfo.repoOwners
        )
        this.$set(this.codeInfo, 'repoOwners', items)
        this.searchRepoOwnerLoading = false
      } else {
        getRepoOwnerByIdAPI(id, query).then(res => {
          this.$set(this.codeInfo, 'repoOwners', res)
          this.searchRepoOwnerLoading = false
        })
      }
    },
    clearRepoOwner () {
      const id = this.source.codehostId
      getRepoOwnerByIdAPI(id).then(res => {
        this.$set(this.codeInfo, 'repoOwners', res)
      })
      this.source.repoName = ''
      this.source.branchName = ''
      this.source.path = ''
      this.source.namespace = ''
      this.source.services = []
      this.$set(this.codeInfo, 'repos', [])
      this.$set(this.codeInfo, 'branches', [])
    },
    getRepoOwnerById (id, key = '') {
      const codehost = this.allCodeHosts.find(item => {
        return item.id === id
      })
      const type = codehost ? codehost.type : 'gitlab'
      this.source.gitType = type
      this.$refs.sourceForm.clearValidate()
      this.$set(this.codeInfo, 'repoOwners', [])
      this.$set(this.codeInfo, 'repos', [])
      this.$set(this.codeInfo, 'branches', [])
      getRepoOwnerByIdAPI(id, key).then(res => {
        this.$set(this.codeInfo, 'repoOwners', res)
      })
      this.source.repoOwner = ''
      this.source.repoName = ''
      this.source.branchName = ''
      this.source.path = ''
      this.source.namespace = ''
      this.source.services = []
    },
    getBranchInfoById (id, repoOwner, repoName, row) {
      const repoItem = this.codeInfo.repos.find(item => {
        return item.name === repoName
      })
      if (repoItem) {
        this.source.namespace = repoItem.namespace
      } else {
        // for manual input
        this.source.namespace = repoOwner
      }
      if (repoName && repoOwner) {
        getBranchInfoByIdAPI(id, this.source.namespace, repoName).then(res => {
          this.$set(this.codeInfo, 'branches', res)
        })
        this.source.branchName = ''
        this.source.path = ''
        this.source.services = []
      }
    },
    refreshService (node, data) {
      if (data.source === 'template') {
        this.currentUpdatedServiceName = data.service_name
        this.currentUpdatedServiceTemplateId = data.create_from.template_id
        this.currentUpdatedServiceAutoSync = data.auto_sync
        this.currentUpdatedServiceVariableYaml = data.estimated_merged_variable
        this.currentUpdatedServiceVariableKvs = data.estimated_merged_variable_kvs
        this.openImportYamlDialog = true
      } else {
        this.dialogImportFromRepoVisible = true
        this.currentUpdatedServiceName = data.service_name
        this.source.codehostId = data.codehost_id
        this.source.repoOwner = data.repo_owner
        this.source.repoName = data.repo_name
        this.source.branchName = data.branch_name
        this.source.path = data.load_path
        this.source.gitType = data.source
        this.source.isDir = data.is_dir
        this.source.serviceName = data.service_name
        this.source.namespace = data.repo_namespace
        this.getInitRepoInfo(this.source)
        validPreloadService(
          data.codehost_id,
          data.repo_namespace,
          data.repo_name,
          data.branch_name,
          data.load_path,
          data.service_name,
          data.is_dir,
          data.remote_name
        ).then(
          res => {
            this.disabledReload = false
          },
          () => {
            this.disabledReload = true
          }
        )
      }
    },
    deleteService (node, data) {
      this.previousNodeKey = ''
      if (data.status === 'named') {
        const index = this.services.findIndex(d => d.label === data.label)
        this.services.splice(index, 1)
      } else {
        let deleteText = ''
        const title = this.$t('global.confirm')
        if (data.type === 'k8s') {
          deleteText = this.$t('services.k8s.confirmToDeleteService', {
            serviceName: data.service_name
          })
        }
        this.$confirm(`${deleteText}`, `${title}`, {
          confirmButtonText: this.$t(`global.confirm`),
          cancelButtonText: this.$t(`global.cancel`),
          type: 'warning'
        }).then(() => {
          deleteProjectServiceAPI(
            data.service_name,
            data.type,
            this.projectName,
            data.visibility
          ).then(() => {
            this.$message.success(this.$t('services.k8s.deleteServiceSuccess'))
            this.$emit('update:showNext', true)
            this.$emit('onDeleteService', data.service_name)
            this.$emit('onRefreshService')
            this.getServiceGroup()
            const parent = node.parent
            const children = parent.data.children || parent.data
            const index = children.findIndex(d => d.id === data.id)
            children.splice(index, 1)
          })
        })
      }
    },
    askSaveYamlConfig (switchNode = false) {
      return this.$confirm(
        this.$t('services.k8s.serviceIsNotSaved'),
        this.$t('global.tips'),
        {
          distinguishCancelAndClose: true,
          confirmButtonText: this.$t(`global.save`),
          cancelButtonText: this.$t(`global.cancel`),
          type: 'warning'
        }
      ).then(() => {
        this.$emit('updateYaml', switchNode)
      })
    },
    selectService (data, node, current) {
      const levelOneNodeLabel =
        node.level === 1 ? node.label : node.parent.label
      // When switching nodes and yaml changed
      if (
        this.previousNodeKey &&
        this.previousNodeKey !== levelOneNodeLabel &&
        this.yamlChange
      ) {
        // Switch to current node
        this.setServiceSelected(this.previousNodeKey)
        this.askSaveYamlConfig(true)
          .then(() => {
            this.justStoreSwitchNode = { data, node, levelOneNodeLabel }
          })
          .catch(action => {
            if (action === 'cancel') {
              this.justStoreSwitchNode = { data, node, levelOneNodeLabel }
              this.selectAndSwitchTreeNode()
            } else if (action === 'close') {
              console.log('关闭')
            }
          })
      } else {
        this.switchTreeNode(data, node, levelOneNodeLabel)
      }
    },
    selectAndSwitchTreeNode () {
      const { data, node, levelOneNodeLabel } = this.justStoreSwitchNode
      this.setServiceSelected(levelOneNodeLabel)
      this.switchTreeNode(data, node, levelOneNodeLabel)
      this.justStoreSwitchNode = {}
    },
    switchTreeNode (data, node, levelOneNodeLabel) {
      this.previousNodeKey = levelOneNodeLabel
      if (data.type === 'kind') {
        const parentService = node.parent.data
        const routeService = this.$route.query.service_name
        if (parentService.service_name !== routeService) {
          this.$router.replace({
            query: {
              service_name: parentService.service_name,
              rightbar: this.$route.query.rightbar
                ? this.$route.query.rightbar
                : 'var',
              kind: data.kind
            }
          })
          this.$emit('onSelectServiceChange', parentService)
        }
        this.$emit('onJumpToKind', data)
      } else {
        this.$router.replace({
          query: {
            service_name: data.service_name,
            rightbar: this.$route.query.rightbar
              ? this.$route.query.rightbar
              : 'var'
          }
        })
        this.$emit('onSelectServiceChange', data)
      }
    },
    setServiceSelected (key) {
      this.$nextTick(() => {
        this.$refs.serviceTree.setCurrentKey(key)
      })
    },
    importYamlSuccess (serviceName) {
      this.$emit('update:showNext', true)
      this.$emit('onShowJoinToEnvBtn', true)
      this.$emit('onRefreshService')
      this.$router.replace({
        query: { service_name: serviceName, rightbar: 'var' }
      })
    },
    importServiceFromNamespaceSuccess () {
      this.$emit('update:showNext', true)
      this.$emit('onShowJoinToEnvBtn', true)
      this.$emit('onRefreshService')
    },
    listenResize () {
      window.screenHeight = document.body.clientHeight
      const serviceTree = this.$refs.serviceTree
      const screenHeight = window.screenHeight - 400
      this.$nextTick(() => {
        serviceTree.$el.style.maxHeight = screenHeight + 180 + 'px'
      })
    }
  },
  computed: {
    deployType () {
      return 'k8s'
    },
    projectName () {
      return this.$route.params.project_name
    },
    filteredServices () {
      const services = this.$utils.filterObjectArrayByKey(
        'service_name',
        this.searchService,
        this.services
      )
      return services.map((element, index) => {
        element.label = element.service_name
        element.id = index
        element.children = []
        return element
      })
    },
    showSelectFileBtn () {
      return (
        this.source.codehostId &&
        this.source.repoName !== '' &&
        this.source.branchName !== ''
      )
    },
    queryServiceName () {
      return this.$route.query.service_name
    },
    sourceRules () {
      return {
        url: [
          {
            required: true,
            message: this.$t('repository.prompt.inputAddress'),
            trigger: ['blur', 'change']
          }
        ]
      }
    },
    serviceRules () {
      const validateServiceName = (rule, value, callback) => {
        if (value === '') {
          callback(new Error(this.$t('services.common.inputServiceName')))
        } else if (
          this.filteredServices.map(ser => ser.service_name).includes(value)
        ) {
          callback(new Error(this.$t('services.k8s.serviceNameIsDuplicated')))
        } else {
          if (!/^[a-z0-9-]+$/.test(value)) {
            callback(new Error(this.$t('services.k8s.checkServiceName')))
          } else {
            callback()
          }
        }
      }
      return {
        newServiceName: [
          {
            type: 'string',
            required: true,
            validator: validateServiceName,
            trigger: ['blur', 'change']
          }
        ]
      }
    }
  },
  watch: {
    filteredServices: {
      handler (val, old_val) {
        this.$nextTick(() => {
          let data = null
          const serviceInRoute = val.find(
            d => d.service_name === this.queryServiceName
          )
          if (serviceInRoute) {
            data = serviceInRoute
          } else {
            data = val[0]
          }
          if (data && !this.showNewServiceInput) {
            this.setServiceSelected(data.service_name)
            const query = {
              service_name: data.service_name,
              rightbar:
                data.status === 'named'
                  ? 'help'
                  : this.$route.query.rightbar
                    ? this.$route.query.rightbar
                    : 'var'
            }
            this.$router.replace({
              query: query
            })
            this.$emit('onSelectServiceChange', data)
          }
        })
        this.$nextTick(() => {
          this.listenResize()
        })
      }
    },
    currentServiceYamlKinds: {
      handler (val, old_val) {
        this.$nextTick(() => {
          const kinds = val.payload.map(element => {
            return {
              kind: element.kind,
              type: 'kind',
              label: `${element.kind}.yaml`.toLowerCase(),
              service_name: `${element.kind}.yaml`.toLowerCase()
            }
          })
          const node = this.$refs.serviceTree.getNode(val.service_name)
          node.childNodes = []
          if (node.data.type === 'k8s') {
            kinds.forEach(element => {
              this.$refs.serviceTree.append(element, node)
            })
          }
        })
      }
    }
  },
  created () {
    this.getServiceGroup()
  },
  mounted () {
    window.addEventListener('resize', this.listenResize)
  },
  beforeDestroy () {
    window.removeEventListener('resize', this.listenResize)
  },
  components: {
    GitFileTree,
    ImportFromTemplate,
    ImportFromNamespace
  }
}
</script>

<style lang="less" >
@import '~@assets/css/component/service-tree.less';
</style>
